import { BaseMode } from "./interface";
import { Utils } from "./util";

let util = new Utils();
export class DecoratorTest implements BaseMode{
    run(){
        function f() {
            util.log("f(): evaluated","decorator");
            return function (target:any, propertyKey: string, descriptor: PropertyDescriptor) {
                util.log("f(): called","decorator");
                util.debug(target,propertyKey,descriptor);
            }
        }

        function g() {
            util.log("g(): evaluated","decorator");
            return function (target:any, propertyKey: string, descriptor: PropertyDescriptor) {
                util.log("g(): called","decorator");
                util.debug(target,propertyKey,descriptor);
            }
        }

        class C {
            @f() // call second
            @g() // call first
            method():void {
                // call last
                util.log("class c method called","decorator");
            }
        }
        let c = new C();
        c.method();
    }
}


import "reflect-metadata";
//类装饰器
@sealed //sealed the class
class Greeter {
    //属性装饰器
    // @format("Hello, %s")
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    // 方法装饰器
    @enumerable(false)
    // @validate
    greet(@required name:string) {
        let formatString = getFormat(this, "greeting");
        return formatString.replace("%s", this.greeting);
        // return "Hello, " + this.greeting;
    }
}
const formatMetadataKey = Symbol("format");
function format(formatString: string) {
    return Reflect.metadata(formatMetadataKey, formatString);
}
function getFormat(target: any, propertyKey: string) {
    return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}


const requiredMetadataKey = Symbol("required");
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
    let existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
    existingRequiredParameters.push(parameterIndex);
    Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey);
}

// function validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<Function>) {
//     let method = descriptor.value as Function;
//     descriptor.value = function () {
//         let requiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName);
//         if (requiredParameters) {
//             for (let parameterIndex of requiredParameters) {
//                 if (parameterIndex >= arguments.length || arguments[parameterIndex] === undefined) {
//                     throw new Error("Missing required argument.");
//                 }
//             }
//         }
//         return method.apply(this, arguments);
//     }
// }


function sealed(constructor: Function) {
    Object.seal(constructor);
    Object.seal(constructor.prototype);
}

function enumerable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.enumerable = value;
    };
}

class Point {
    private _x: number;
    private _y: number;
    constructor(x: number, y: number) {
        this._x = x;
        this._y = y;
    }

    //访问器装饰器
    @configurable(false)
    get x() { return this._x; }

    @configurable(false)
    get y() { return this._y; }
}
function configurable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.configurable = value;
    };
}